﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Facebook;

namespace FeedBack {
    public class NetworkStoryParser : IStoryParser {
        private string initPath;
        private FacebookClient fb;
        private DateTime threshold;
        private int i;
        private Queue<JsonArray> queue = new Queue<JsonArray>();
        private bool done;
        private bool started;

        public string CompleteStatus { get; private set; }

        private static object lockObject = new object();

        public NetworkStoryParser(FacebookClient fb, string initPath, DateTime threshold, int i) {
            this.initPath = initPath;
            this.fb = fb;
            this.threshold = threshold;
            this.i = i;
        }

        private void Download() {
            for (int i = 0; i < 3; i++) {
                try {
                    JsonObject result = fb.Get(initPath) as JsonObject;
                    JsonArray data = result["data"] as JsonArray;

                    int queryStringPos = initPath.IndexOf("?");
                    if (queryStringPos >= 0) {
                        initPath = initPath.Substring(0, queryStringPos);
                    }
                    string basePath = initPath.Substring(0, initPath.IndexOf("/"));

                    var jsonBackupPath = Path.Combine(Configuration.BackupFolder, "json", DateTime.Now.ToString("yyyyMMddHHmmss"));
                    jsonBackupPath.EnsureDirectory();
                    File.WriteAllText(Path.Combine(jsonBackupPath, string.Format("{1}.{0:000}.json", i++, initPath.Replace("/", "_").RemoveIllegalPathCharacters())),
                                      result.ToString());

                    for (; ; ) {

                        queue.Enqueue(data);
                        foreach (JsonObject story in data) {
                            if (DateTime.Parse(story["updated_time"] as string) < threshold) {
                                CompleteStatus = "All feed entries downloaded";
                                done = true;
                                return;
                            }
                        }

                        if (!result.ContainsKey("paging")) {
                            CompleteStatus = "All feed entries downloaded";
                            done = true;
                            return;
                        }

                        JsonObject paging = result["paging"] as JsonObject;
                        Uri uri = new Uri(paging["next"].ToString());
                        string url = uri.PathAndQuery;
                        url = basePath + url.Substring(url.IndexOf("/", 10));

                        for (int j = 0; j < 10; j++) {

                            try {
                                Thread.Sleep(1000);
                                lock (lockObject) {
                                    result = fb.Get(url) as JsonObject;
                                }
                                break;
                            }
                            catch (FacebookApiException) {
                                for (int k = 0; k < 60; k++) {
                                    System.Threading.Thread.Sleep(1000);
                                    Debug.WriteLine(string.Format("{0} seconds elapsed", k));
                                }
                            }
                            catch (Exception e) {
                                if (!e.Message.Contains("time")) {
                                    CompleteStatus = e.Message;
                                    done = true;
                                    return;
                                }
                            }
                        }

                        File.WriteAllText(Path.Combine(jsonBackupPath, string.Format("{1}.{0:000}.json", i++, initPath.Replace("/", "_").RemoveIllegalPathCharacters())),
                                          result.ToString());

                        data = result["data"] as JsonArray;

                        if (!result.Keys.Contains("paging")) {
                            done = true;
                            break;
                        }
                    }

                    break;


                }
                catch (Exception e) {
                    for (int k = 0; k < 60; k++) {
                        System.Threading.Thread.Sleep(1000);
                        Debug.WriteLine(string.Format("{0} seconds elapsed", k));
                        CompleteStatus = e.Message;
                    }
                }
            }

            done = true;
        }

        public void Start() {
            if (!started) {
                ThreadPool.QueueUserWorkItem((x) => this.Download());
                started = true;
            }
        }

        public IEnumerable<Facebook.JsonObject> GetStories() {
            this.Start();

            for (; !done || queue.Any(); ) {
                if (queue.Any()) {
                    var stories = queue.Dequeue();
                    foreach (JsonObject story in stories) {
                        if (DateTime.Parse(story["updated_time"] as string) < threshold) {
                            CompleteStatus = "All feed entries processed";
                            done = true;
                            break;
                        }

                        yield return story;
                    }
                }
                else {
                    Thread.Sleep(1000);
                }
            }
        }
        
    }
}
